﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="Microsoft Corp." file="RestServiceClient.cs">
//   All rights reserved. See License.txt in the project root for license information.
// </copyright>
// 
// --------------------------------------------------------------------------------------------------------------------
namespace RestClient
{
    using System;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;

    public class RestServiceClient
    {
        protected readonly IRestServiceContext ServiceContext;

        public RestServiceClient(IRestServiceContext serviceContext)
        {
            this.ServiceContext = serviceContext;
        }

        protected async Task<WebResponse> ExecuteCommand(Func<IRestOperation> operationFactory, RequestOptions options)
        {
            if (options != null)
            {
                options.OperationContext = new OperationContext { StartTime = DateTimeOffset.UtcNow };
            }

            var restCommand = operationFactory();
            var response = await this.ExecuteCommand(restCommand, options, this.ServiceContext);

            
            if (options != null)
            {
                options.OperationContext.EndTime = DateTimeOffset.UtcNow;
            }

            return response;
        }

        private async Task<WebResponse> ExecuteCommand(IRestOperation command, RequestOptions options, IRestServiceContext context)
        {
            if (options == null)
            {
                return await command.Execute();
            }

            var retryCount = 0;

            do
            {
                try
                {
                    return await command.Execute();
                }
                catch (AggregateException e)
                {
                    var webException = e.InnerException as WebException;
                    if (options.RetryPolicy == null || webException == null)
                    {
                        throw;
                    }

                    var response = webException.Response as HttpWebResponse;
                    if (response == null)
                    {
                        throw;
                    }

                    var retryIn = options.RetryPolicy.RetryIn(retryCount, response.StatusCode, webException, context);
                    if (retryIn == TimeSpan.Zero)
                    {
                        throw;
                    }

                    Thread.Sleep(retryIn);

                    retryCount++;
                }
            } 
            while (true);
        }
    }
}